<template>
	<view class="container">
		<view style="text-align: center;margin: 20rpx;padding-top: 20rpx;">
			<text style="color: #4f6bfe;">已接入</text>
		</view>
		<view class="top-title">
			<view class="ai-class" :class="selClass==='deepseek'&&'sel-ai-class'" @click="clickAiClass('deepseek')">
				<image mode="" style="width: 240rpx;" class="top-title-img" src="@/static/deepseek.webp" />
			</view>
			<view class="ai-class" :class="selClass==='qwen'&&'sel-ai-class'" @click="clickAiClass('qwen')">
				<image mode="" class="top-title-img" src="@/static/tongyi.png" />
				<text>通义千问</text>
			</view>
			<view class="ai-class" :class="selClass==='kimi'&&'sel-ai-class'" @click="clickAiClass('kimi')">
				<image mode="" class="top-title-img" src="@/static/kimi.webp" />
				<text>Kimi</text>
			</view>
		</view>
		<view class="msg-box">
			<view class="msg-list" v-for="(item,idx) in msgList">
				<view class="my-msg">
					<view class="my-msg-panel">
						{{item.problem}}
					</view>
				</view>
				<view class="msg-type">
					<view class="msg-type-panel" v-if="item.sendLoading">
						{{selClass}}思考中
						<text class="sendIng">.</text>
						<text class="sendIng">.</text>
						<text class="sendIng">.</text>
					</view>
					<view class="msg-type-panel" v-else-if="item.isTimeout">
						{{selClass}}服务器繁忙
					</view>
					<view class="msg-type-panel" v-else>
						{{selClass}}思考完成
					</view>
				</view>
				<view class="msg-answer">
					<img class="answer-img" :src="require('@/static/ai.png')" v-if="item.answer" />
					<view ref='domStr' class="answer-info markdown-body" v-html="item.markerHtml"></view>
				</view>
			</view>
		</view>
		<view class="input-box-panel">
			<view style="font-size: 32rpx;color:grey">{{speechResult}}</view>
			<view>{{time}}s后将结束录音,并发送您的问题</view>
			<view class="input-box">
				<view class="fake-input" ref="editor" @input="handleInput" contenteditable="true"
					 :placeholder="placeholderStr" @keyup.enter="send"></view>
				<view class="button-box">
					<button type="primary" @click="startSpeech">{{speakText}}</button>
					<button type="primary" @click="send">发送</button>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import marked from "@/js/marked.min.js"
	export default {
		data() {
			return {
				timmer:null,
				selClass:"deepseek",
				placeholderStr:"你可以问我任何问题",
				answerList:[],
				msgList:[],
				answerTimmer:{},
				content:'',
				index:0,
				config:{
					apiUrl: 'https://zyykjcgzhxt.cdutcm.edu.cn/api'
				},
				speechStatus:false,
				speakText:'语音输入',
				countDown:null,
				speechResult:'',
				timer:null,
				time:6,
			}
		},
		onLoad() {
			window.marked = marked
		},
		methods: {
			clickAiClass(type) {
				if (this.selClass === type) return;
				this.answerList=[]
				this.selClass = type;
				this.msgList = [];
			},
			handleInput() {
				if (this.timmer) {
					clearTimeout(this.timmer);
				}
				this.timmer = setTimeout(() => {
					const innerStr = this.$refs.editor.$el.innerHTML;
					if (innerStr === "<br>") {
						this.$refs.editor.$el.innerHTML = "";
						this.content = "";
					} else {
						this.content = this.$refs.editor.$el.innerText;
					}
					this.content = this.content.trim();
					if (this.content !== "") {
						this.placeholderStr = "";
					} else {
						this.placeholderStr = "你可以问我任何问题";
					}
				}, 100);
			},
			send(e) {
				if (!this.content) {
					uni.showModal({
						content: '请输入您要询问的内容',
						showCancel: false
					});
					return
				}
				this.$refs.editor.$el.innerHTML = "";
				this.placeholderStr = "你可以问我任何问题";
				this.msgList.push({
					problem: this.content + "",
					answer: "",
					sendLoading: true,
					isTimeout: false,
				});
			
				let timer = setTimeout(() => {
					this.msgList[key].sendLoading = false;
					this.msgList[key].isTimeout = true;
					console.error("连接超时");
					sse.close(); // 关闭连接
				}, 280000);
			
				const key = this.msgList.length - 1;
				let sse = null;
				sse = new EventSource(
					this.config.apiUrl + `/atFrontAchievement/callAiQuestions?content=${this.content}&type=${this.selClass}`
				);
			
				sse.onmessage = (event) => {
					clearTimeout(timer);
					const data = event.data;
					if (this.answerList[key]) {
						this.answerList[key].push(data);
					} else {
						this.answerList[key] = [data];
					}
					this.showAnswer(key);
				};
				sse.onerror = (error) => {
					clearTimeout(timer);
					this.msgList[key].sendLoading = false;
					console.error("Error occurred:", error);
					sse.close();
				};
			},
			showAnswer(key) {
				if (this.answerTimmer[key]) return;
				// const data = this.answerList[key].join("");
				let data = ''
			
				this.answerTimmer[key] = setTimeout(() => {
					this.answerList[key].reduce((prev, item, index) => {
						if (item === '') {
							item = ' '
						}
						if (item !== '#' && this.answerList[key][index + 1] === '#' && this.answerList[key][index + 2] === '#' && this.answerList[key][index + 3] === '#') {
							item = item + '<br/>'
						}
						if (item === '#' && this.answerList[key][index - 2] === '#' && this.answerList[key][index - 1] === '#') {
							item = item + '<br/>'
						}
						if (item === '-' && prev === ' ') {
							item = "<br/>-"
						}
						data += item
					}, '')
					this.msgList[key].answer = data;
					this.msgList[key].markerHtml = ''
					let that = this
					function printOneByOne() {
						if (that.index >= data.length) {
							console.log('已经拼完');
							that.index = 0
							that.msgList[key].markerHtml = window.marked.parse(data);
							that.$refs.domStr[key].innerHTML = window.marked.parse(that.msgList[key].answer)
							that.answerTimmer[key] = null
							that.content = ''
						} else {
							setTimeout(() => {
								that.$refs.domStr[key].$el.innerHTML += data[that.index]
								that.index++
								printOneByOne()
							}, 30)
						}
					}
					printOneByOne()
				}, 500);
			},
			//启用语音录制
			startSpeech() {
				//#ifdef H5
				console.log('开始语音输入');
				// 录制音频逻辑
				this.speechStatus = true
				if (this.speechStatus) {
					if ('webkitSpeechRecognition' in window) {
						const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)(); // 注意这里用的是webkit前缀，因为标准的SpeechRecognition在某些浏览器中可能需要前缀或者polyfill。
						recognition.lang = 'zh-CN'; // 设置语言为中文
						recognition.interimResults = false; // 设置为false，表示只返回最终结果，不返回中间结果
						if (this.speakText === "取消录音") {
							this.speakText = "语音输入"
							this.speechStatus = false
							this.stopTimer()
							clearTimeout(this.countDown)
							recognition.stop();
							this.send()
							return
						}
						this.startTimer()
						recognition.onresult = (event) => {
							const last = event.results.length - 1;
							this.speechResult = event.results[last][0].transcript; // 获取识别结果并赋值给data中的transcript
							this.content = this.speechResult
							this.countDown = setTimeout(() => {
								recognition.stop();
								this.send()
							}, 6000)
			
						};
						recognition.onerror = (event) => {
							console.error('Speech recognition error:', event.error);
						};
						recognition.start(); // 开始语音识别
						this.speakText = '取消录音'
					} else {
						alert('您的浏览器不支持语音识别功能');
					}
				}
				//#endif
			},
			startTimer(){
				this.timer = setInterval(() => {
					if (this.time <= 0) {
						this.time = 7
						this.speakText = "语音输入"
						clearInterval(this.timer)
					}
					this.time--
				}, 1000)
			},
			stopTimer() {
				clearInterval(this.timer)
				this.speakText = "语音输入"
				this.time = 6
			}
			
		}
	}
</script>

<style lang="scss" scoped>
@import "../../style/markdownStyle.css";
.container{
	box-sizing: border-box;
	 .input-box-panel {
	        padding-top: 20rpx;
			margin: 20rpx;
	    }
	    .input-box {
	        border: solid 2rpx #b6adff;
	        border-radius: 16rpx;
	        padding: 20rpx;
	    }
	    .fake-input {
	        border: none;
	        outline: unset;
	    }
	    .fake-input::after {
	        color: #9195a3;
	        content: attr(placeholder);
	    }
	    .button-box {
	        margin-top: 20rpx;
			display: flex;
			justify-content: end;
			button{
				margin: 0;
				margin: 10rpx;
			}
	    }
	
	    .msg-box {
	        padding-bottom: 40rpx;
	        max-height: 60vh;
	        overflow: auto;
	        padding: 0 40rpx;
	    }
	
	    .my-msg {
	        text-align: right;
	    }
	    .my-msg-panel {
	        text-align: left;
	        background-color: #ddd9ff;
	        font-size: 32rpx;
	        font-weight: bold;
	        color: #333;
	        display: inline-block;
	        padding: 10rpx 20rpx;
	        border-radius: 16rpx;
	        max-width: 1200rpx;
	    }
	
	    .msg-type-panel {
	        background-color: #f4f1ff;
	        font-size: 28rpx;
	        color: #704cfc;
	        display: inline-block;
	        padding: 10rpx 16rpx;
	        border-radius: 8rpx;
	    }
	    .msg-process {
	        font-size: 30rpx;
	        color: #666;
	        padding: 10rpx 20rpx;
	        border-left: solid 2rpx #eee;
	        margin-top: 40rpx;
	    }
	    .msg-answer {
	        color: #333;
	        font-size: 30rpx;
	        margin-top: 20rpx;
	        display: flex;
	    }
	    .top-title {
	        display: flex;
	        align-items: center;
	        color: #4f6bfe;
	        margin-bottom: 80rpx;
			flex-wrap: wrap;
			box-sizing: border-box !important;
	    }
	    .top-title-img {
			width: 50rpx;
	        height: 50rpx;
	        margin-right: 20rpx;
	    }
		
	    .ai-class {
			box-sizing: border-box !important;
			margin: 20rpx;
			width: calc(50% - 40rpx);
	        display: flex;
	        align-items: center;
			justify-content: center;
	        cursor: pointer;
	        box-shadow: 0 0 4rpx 2rpx rgba(79, 107, 254, 0.2);
	        padding: 10rpx 40rpx;
	        border-radius: 8rpx;
	        text-align: center;
	        font-size: 28rpx;
	        font-weight: bold;
	        color: #333;
	    }
	    .ai-class:hover {
	        box-shadow: 0 0 4rpx 2rpx rgba(79, 107, 254, 1);
	    }
	    .sel-ai-class {
	        box-shadow: 0 0 4rpx 2rpx rgba(79, 107, 254, 1);
	    }
	    .online-type {
	
	        margin-right: 20rpx;
	    }
	    .online-type-a {
	        color: #999;
	        border: solid 2rpx #999;
	    }
	    .answer-img {
	        width: 80rpx;
	        height: 80rpx;
	        flex-shrink: 0;
	        margin-right: 20rpx;
	    }
	    .answer-info {
	        padding: 20rpx 0;
	    }
	    .sendIng {
	        display: inline-block;
	        font-size: 56rpx;
	        line-height: 0;
	    }
	    .sendIng:nth-child(1) {
	        animation: sendIngAnimation 2s linear 0.5s infinite;
	    }
	    .sendIng:nth-child(2) {
	        animation: sendIngAnimation 2s linear 1s infinite;
	    }
	    .sendIng:nth-child(3) {
	        animation: sendIngAnimation 2s linear 1.5s infinite;
	    }
	    @keyframes sendIngAnimation {
	        0% {
	            transform: translateY(0);
	            opacity: 1;
	        }
	        25% {
	            transform: translateY(-10rpx);
	            opacity: 1;
	        }
	        50% {
	            transform: translateY(0);
	            opacity: 1;
	        }
	        75% {
	            transform: translateY(10rpx);
	            opacity: 1;
	        }
	        100% {
	            transform: translateY(0);
	            opacity: 1;
	        }
	    }
	    .online-ico{
	        font-size: 28rpx;
	        margin-right: 10rpx;
	    }
}
</style>
